import socket
import struct
import binascii

import config


def hex_to_float32(hex_str):
    byte_data = bytes.fromhex(hex_str)
    float_value = struct.unpack('>f', byte_data)[0]
    return float_value


def float32_to_hex(float_value): 
    packed_data = struct.pack('>f', float_value)
    hex_str = binascii.hexlify(packed_data).decode('ascii').upper()
    formatted_hex_str = ' '.join(hex_str[i:i+2] for i in range(0, len(hex_str), 2))
    return formatted_hex_str


# crc16生成 低位在前
def crc16_modbus(value):
    """
    计算MODBUS-RTU CRC-16校验码，并返回低字节在前的十六进制字符串。
    :param data: 输入的MODBUS数据（字节序列）
    :return: CRC-16校验码的十六进制字符串（低字节在前）
    """
    data = bytes.fromhex(value.replace(" ", ""))
    crc = 0xFFFF  # 初始化CRC寄存器
    poly = 0xA001  # CRC多项式
    for byte in data:
        crc ^= byte  # 将数据字节与CRC寄存器的低字节进行异或运算
        for _ in range(8):  # 每个数据字节处理8次
            if crc & 0x0001:  # 如果CRC的最低位为1
                crc = (crc >> 1) ^ poly  # 右移一位并与多项式异或
            else:
                crc >>= 1  # 仅右移一位
    # 提取CRC的低字节和高字节
    crc_low_byte = crc & 0x00FF
    crc_high_byte = (crc >> 8) & 0x00FF
    # 格式化为十六进制字符串，并确保低字节在前
    crc_hex = f"{crc_low_byte:02X} {crc_high_byte:02X}"
    return crc_hex


def read_db_commd(dbip, gnm="04"):
    # 读取电表
    # dbip 电表ip 列如01
    # gnm  功能码04 读取
    sendata = f"{dbip} {gnm} 01 00 00 02"
    crc = crc16_modbus(sendata)
    return f"{sendata} {crc}"


def set_dbip_commd(dbip, newip, gnm="10"):
    # 修改电表ip
    # dbip 电表ip 列如01
    # gnm  功能码10 写入
    # newip 修改后的电表ip 传入浮点数列如 3.0
    sendata = f"{dbip} {gnm} 00 08 00 02 04"
    sendata = sendata + " " + float32_to_hex(newip)
    crc = crc16_modbus(sendata)
    return f"{sendata} {crc}"


def clear_dbip_commd(dbip, gnm="10"):
    # 电表清零
    # dbip 电表ip 列如01
    # gnm  功能码10 写入
    sendata = f"{dbip} {gnm} 00 20 00 01 02 55 55"
    crc = crc16_modbus(sendata)
    return f"{sendata} {crc}"


def db_dl_jx(hex_data):
    # 电表返回数据解析 [电表电量]
    byte_data = bytes.fromhex(hex_data.replace(" ", ""))
    data_field = byte_data[3:7].hex()
    if len(data_field) != 8:
        config.err_log("电表解析错误 | [" + byte_data.hex() + " ]")
        return ""
    return hex_to_float32(data_field)


def create_tcp_connection(hex_data):
    data = bytes.fromhex(hex_data.replace(" ", ""))
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            sock.connect((config.CONFIG.CFG["wlip"], int(config.CONFIG.CFG["wlport"])))
            sock.sendall(data)
            sock.settimeout(1)
            response = sock.recv(1024)
            return response.hex()
    except socket.timeout:
        pass
    except Exception as e:
        config.err_log(e)
    return ""